package com.grapro.visitorsystem.exception.handler;

import com.grapro.visitorsystem.entity.JsonResult;
import com.grapro.visitorsystem.exception.CustomException;
import com.grapro.visitorsystem.utils.json.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.ConversionNotSupportedException;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.io.IOException;

@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler { // 参考，https://blog.csdn.net/Mrs_chens/article/details/93615225

    private static final String LOG_EXCEPTION_FORMAT = "Capture Exception By GlobalExceptionHandler: Code: %s Detail: %s";

    // 1. 运行时异常
    @ExceptionHandler(RuntimeException.class)
    public JsonResult runtimeExceptionHandler(RuntimeException ex) {
        return resultFormat(1, ex);
    }

    // 2. 空指针异常
    @ExceptionHandler(NullPointerException.class)
    public JsonResult nullPointerExceptionHandler(NullPointerException ex) {
        System.err.println("NullPointerException:");
        return resultFormat(2, ex);
    }

    // 3. 类型转换异常
    @ExceptionHandler(ClassCastException.class)
    public JsonResult classCastExceptionHandler(ClassCastException ex) {
        return resultFormat(3, ex);
    }

    // 4. IO异常
    @ExceptionHandler(IOException.class)
    public JsonResult iOExceptionHandler(IOException ex) {
        return resultFormat(4, ex);
    }

    // 5. 未知方法异常
    @ExceptionHandler(NoSuchMethodException.class)
    public JsonResult noSuchMethodExceptionHandler(NoSuchMethodException ex) {
        return resultFormat(5, ex);
    }

    // 6. 数组越界异常
    @ExceptionHandler(IndexOutOfBoundsException.class)
    public JsonResult indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
        return resultFormat(6, ex);
    }

    // 7. 400错误
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public JsonResult requestNotReadable(HttpMessageNotReadableException ex) {
        System.out.println("400..requestNotReadable");
        return resultFormat(7, ex);
    }

    // 8. 400错误
    @ExceptionHandler({TypeMismatchException.class})
    public JsonResult requestTypeMismatch(TypeMismatchException ex) {
        System.out.println("400..TypeMismatchException");
        return resultFormat(8, ex);
    }

    // 9. 400错误
    @ExceptionHandler({MissingServletRequestParameterException.class})
    public JsonResult requestMissingServletRequest(MissingServletRequestParameterException ex) {
        System.out.println("400..MissingServletRequest");
        return resultFormat(9, ex);
    }

    // 10. 405错误
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public JsonResult request405(HttpRequestMethodNotSupportedException ex) {
        return resultFormat(10, ex);
    }

    // 11. 406错误
    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
    public JsonResult request406(HttpMediaTypeNotAcceptableException ex) {
        System.out.println("406...");
        return resultFormat(11, ex);
    }

    // 12. 500错误
    @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
    public JsonResult server500(RuntimeException ex) {
        System.out.println("500...");
        return resultFormat(12, ex);
    }

    // 13. 栈溢出
    @ExceptionHandler({StackOverflowError.class})
    public JsonResult requestStackOverflow(StackOverflowError ex) {
        return resultFormat(13, ex);
    }

    // 14. 除数不能为0
    @ExceptionHandler({ArithmeticException.class})
    public JsonResult arithmeticException(ArithmeticException ex) {
        return resultFormat(14, ex);
    }

    // 15. 自定义错误
    @ExceptionHandler(CustomException.class)
    public JsonResult handleException(CustomException ex) {
        log.error("### 异常信息:{} ###", ex.getMessage());
        return resultFormat(15, ex);
    }

    // 16. 其他错误
    @ExceptionHandler({Exception.class})
    public JsonResult exception(Exception ex) {
        return resultFormat(16, ex);
    }

    private <T extends Throwable> JsonResult resultFormat(Integer code, T ex) {
        ex.printStackTrace();
        log.error(String.format(LOG_EXCEPTION_FORMAT, code, ex.getMessage()));
        return JsonUtil.error(code, ex.getMessage());
    }

}